// ****************************************************************************
// @File: SmartPtrContext.h
//
// PURPOSE: the static class representing the context during the whole GC process
// AUTHOR:  Zj Ai
//
// NOTES: 
//     
// HISTORY:
//
//   ------ Zj Ai  05/08/2012 creating the file
//
// @EndHeader@
// ****************************************************************************
#pragma once
#include "stdafx.h"
#include "GlobalDefinition.h"

class CSmartPtrContext
{
public:
	// set the global variables' initial value 
	static void SetInitialValue()
	{   
		//The context has been initialized.
		CSmartPtrContext::s_bIsValid = true;
	}

	static void InvalidateContext()
	{
		CSmartPtrContext::s_bIsValid = false;
	}

	// Create StopGcThreadEvet 
	static void CreateStopGcThreadEvent()
	{
		if (s_hStopGcThreadEvent == NULL)
		{
			s_hStopGcThreadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		}
	}

	static HANDLE& GetStopGcThreadEvent()
	{
		EnsureContextValid();
		return s_hStopGcThreadEvent;
	}

	static void CloseStopGcThreadEvent()
	{
		CLOSE_HANDLE_IF_NOT_NULL(s_hStopGcThreadEvent);
	}

	// Stop Replay Event inside replay engine.
	static void CreateNeedGcEvent()
	{
		if (s_hNeedGcEvent == NULL)
		{
			s_hNeedGcEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		}
	}

	static HANDLE& GetNeedGcEvent()
	{
		EnsureContextValid();
		return s_hNeedGcEvent;
	}

	static void CloseNeedGcEvent()
	{
		CLOSE_HANDLE_IF_NOT_NULL(s_hNeedGcEvent);
	}

	// Stop Replay Event inside replay engine.
	static void CreateGcThreadAlreadyStoppedEvent()
	{
		if (s_hGcThreadAlreadyStoppedEvent == NULL)
		{
			s_hGcThreadAlreadyStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
		}
	}

	static HANDLE& GetGcThreadAlreadyStoppedEvent()
	{
		EnsureContextValid();
		return s_hGcThreadAlreadyStoppedEvent;
	}

	static void CloseGcThreadAlreadyStoppedEvent()
	{
		CLOSE_HANDLE_IF_NOT_NULL(s_hGcThreadAlreadyStoppedEvent);
	}

	// is collecting?
	static bool IsCollecting()
	{
		EnsureContextValid();
		return CSmartPtrContext::s_bCollecting;
	}

	static void SetIsCollecting(bool bIsCollecting)
	{
		CSmartPtrContext::s_bCollecting = bIsCollecting;
	}

	// GC generation set & get
	static void SetNeedGcGeneration(int generation)
	{
		CSmartPtrContext::s_iNeedGcGeneration = generation;
	}
	
	static int GetNeedGcGeneration()
	{
		return CSmartPtrContext::s_iNeedGcGeneration;
	}

	// get and set collected objects
	static void SetLastGcCollectedObjs(int collectedObjs)
	{
		CSmartPtrContext::s_iCollectedObjs = collectedObjs;
	}

	static int GetLastGcCollectedObjs()
	{
		return CSmartPtrContext::s_iCollectedObjs;
	}

private:
	static void EnsureContextValid()
	{
		if (!CSmartPtrContext::s_bIsValid)
		{
			// TODO: learn what they have done towards the exception
			// CExceptionHelper::Throw(DREPLAY_E_INVALID_REPLAY_CONTEXT);            
		}
	}

private:
	static bool s_bIsValid;
	
	// event indicate the tread should stop
	static HANDLE s_hStopGcThreadEvent;
	
	// event indicate we need GC
	static HANDLE s_hNeedGcEvent;

	// event indicate the Gc thread normally stopped
	static HANDLE s_hGcThreadAlreadyStoppedEvent;

	// is collecting garbage?
	static bool s_bCollecting;

	// which generation needs to be collect?
	static int s_iNeedGcGeneration;

	// objects that is collected from the last GC
	static UINT s_iCollectedObjs;
};
